
template<class T> class Luna {
  public:
    static void Register(lua_State *L) {
	  lua_pushcfunction(L, &Luna<T>::constructor);	// cfunction
      lua_setglobal(L, T::className);				// *empty*
      luaL_newmetatable(L, T::className);			// metatable
      lua_pushstring(L, "__gc");					// metatable string
      lua_pushcfunction(L, &Luna<T>::gc_obj);		// metatable string cfunction
      lua_settable(L, -3);							// metatable
    }

    static int constructor(lua_State *L) {
      lua_newtable(L);									// {self}

	  T* obj = new T(L);

      lua_pushnumber(L, 0);								// {self} 0
      T** a = (T**)lua_newuserdata(L, sizeof(T*));		// {self} 0 userd
      *a = obj;
      luaL_getmetatable(L, T::className);				// {self} 0 userd {met}
	  lua_setmetatable(L, -2);							// {self} 0 userd
      lua_settable(L, -3); // table[0] = obj;			// {self}

      for (int i = 0; T::Register[i].name; i++) {		// {self}
        lua_pushstring(L, T::Register[i].name);			// {self} "nameInRegStrct"
        lua_pushnumber(L, i);							// {self} "nameInRS" i
        lua_pushcclosure(L, &Luna<T>::thunk, 1);		// {self} "nameInRS" closure
        lua_settable(L, -3);							// {self}
      }
      return 1;
    }

    static int thunk(lua_State *L) {
      int i = (int)lua_tonumber(L, lua_upvalueindex(1));
      lua_pushnumber(L, 0);
      lua_gettable(L, 1);

      T** obj = static_cast<T**>(luaL_checkudata(L, -1, T::className));
      lua_remove(L, -1);
      return ((*obj)->*(T::Register[i].mfunc))(L);
    }

    static int gc_obj(lua_State *L) {
      T** obj = static_cast<T**>(luaL_checkudata(L, -1, T::className));
      delete (*obj);
      return 0;
    }

    struct RegType {
      const char *name;
      int(T::*mfunc)(lua_State*);
    };
};
